﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Windows.Forms;
using WjAutoConfigApp.Models;

namespace WjAutoConfigApp.Common
{
    public class CommomMethod
    {

        #region 表单校验方法


        /// <summary>
        /// 校验是否是整形数据
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static bool IsIntData(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return false;
            }
            return int.TryParse(text, out int result);
        }

        /// <summary>
        /// 校验是否是Double数据
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static bool IsDoubleData(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return false;
            }
            return double.TryParse(text, out double result);
        }

        /// <summary>
        /// 校验是否是float类型数据
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static bool IsFloatData(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return false;
            }
            return float.TryParse(text, out float result);
        }

        #endregion



        #region 输出提示内容

        /// <summary>
        /// 显示错误对话框
        /// </summary>
        /// <param name="msg"></param>
        public static void ShowMsg(string msg)
        {
            if (string.IsNullOrWhiteSpace(msg)) return;
            MessageBox.Show(msg);
        }

        /// <summary>
        /// 显示消息对话框
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static DialogResult ShowInfomationDialog(string msg, string capital)
        {
            return MessageBox.Show(null, msg,
                capital, MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
        }

        /// <summary>
        /// 显示询问对话框
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static DialogResult ShowInquiryDialog(string msg)
        {
            return MessageBox.Show(null, msg, "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
        }
        #endregion

        #region 寻找区域内的所有点

        /// <summary> 
        /// 判断点是否在多边形内. 
        /// ----------原理---------- 
        /// 注意到如果从P作水平向左的射线的话，如果P在多边形内部，那么这条射线与多边形的交点必为奇数， 
        /// 如果P在多边形外部，则交点个数必为偶数(0也在内)。 
        /// </summary> 
        /// <param name="checkPoint">要判断的点</param> 
        /// <param name="polygonPoints">多边形的顶点</param> 
        /// <returns></returns> 
        public static bool IsInPolygon(Point checkPoint, List<Point> polygonPoints)
        {
            bool inside = false;
            int pointCount = polygonPoints.Count;
            Point p1, p2;
            for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一个点和最后一个点作为第一条线，之后是第一个点和第二个点作为第二条线，之后是第二个点与第三个点，第三个点与第四个点... 
            {
                p1 = polygonPoints[i];
                p2 = polygonPoints[j];
                if (checkPoint.Y < p2.Y)
                {//p2在射线之上 
                    if (p1.Y <= checkPoint.Y)
                    {//p1正好在射线中或者射线下方 
                        if ((checkPoint.Y - p1.Y) * (p2.X - p1.X) > (checkPoint.X - p1.X) * (p2.Y - p1.Y))//斜率判断,在P1和P2之间且在P1P2右侧 
                        {
                            //射线与多边形交点为奇数时则在多边形之内，若为偶数个交点时则在多边形之外。 
                            //由于inside初始值为false，即交点数为零。所以当有第一个交点时，则必为奇数，则在内部，此时为inside=(!inside) 
                            //所以当有第二个交点时，则必为偶数，则在外部，此时为inside=(!inside) 
                            inside = (!inside);
                        }
                    }
                }
                else if (checkPoint.Y < p1.Y)
                {
                    //p2正好在射线中或者在射线下方，p1在射线上 
                    if ((checkPoint.Y - p1.Y) * (p2.X - p1.X) < (checkPoint.X - p1.X) * (p2.Y - p1.Y))//斜率判断,在P1和P2之间且在P1P2右侧 
                    {
                        inside = (!inside);
                    }
                }
            }
            return inside;
        }

        /// <summary>
        /// 获取匹配的所有点
        /// </summary>
        /// <param name="points">多边形区域的各个顶点集合</param>
        /// <returns></returns>
        public static List<Point> GetMatchPoints(List<Point> points)
        {
            List<Point> matchPoints = new List<Point>();
            //获取X方向上的最大值和最小值
            var maxX = points.Select(p => p.X).Max();
            var minX = points.Select(p => p.X).Min();
            var maxY = points.Select(p => p.Y).Max();
            var minY = points.Select(p => p.Y).Min();
            for (int y = minY; y <= maxY; y++)
            {
                for (int x = minX; x < maxX; x++)
                {
                    var point = new Point(x, y);
                    if (IsInPolygon(point, points))
                    {
                        matchPoints.Add(point);
                    }
                }
            }
            return matchPoints;
        }


        #endregion

        /// <summary>
        /// 将枚举转为集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<CommonContent> EnumToList<T>()
        {
            List<CommonContent> list = new List<CommonContent>();

            foreach (var e in Enum.GetValues(typeof(T)))
            {
                CommonContent m = new CommonContent();
                object[] objArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (objArr != null && objArr.Length > 0)
                {
                    DescriptionAttribute da = objArr[0] as DescriptionAttribute;
                    m.Value = da.Description;
                }
                m.Code = Convert.ToInt32(e);
                list.Add(m);
            }
            return list;
        }

        /// <summary>
        /// 判断图片是否索引像素格式,是否是引发异常的像素格式
        /// </summary>
        /// <param name="imagePixelFormat">图片的像素格式</param>
        /// <returns></returns>
        public static bool IsIndexedPixelFormat(PixelFormat imagePixelFormat)
        {
            PixelFormat[] pixelFormatArray = {
                                            PixelFormat.Format1bppIndexed
                                            ,PixelFormat.Format4bppIndexed
                                            ,PixelFormat.Format8bppIndexed
                                            ,PixelFormat.Undefined
                                            ,PixelFormat.DontCare
                                            ,PixelFormat.Format16bppArgb1555
                                            ,PixelFormat.Format16bppGrayScale
                                        };
            foreach (PixelFormat pf in pixelFormatArray)
            {
                if (imagePixelFormat == pf)
                {
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// 保存已完成的区域图形
        /// </summary>
        /// <param name="color"></param>
        public static void SaveFinishArea(AreaModel areaModel)
        {
            //将已经画过的区域保存起来
            Point[] copyPoints = new Point[areaModel.Points.Count];
            areaModel.Points.CopyTo(copyPoints);
            var model = new AreaModel {
                PenColor = areaModel.PenColor,
                IsSaved = areaModel.IsSaved,
                Points = copyPoints.ToList(),
                IsLaneArea = areaModel.IsLaneArea,
                LaneInfoModel = BinaryDeepCopy(areaModel.LaneInfoModel),
                PropertyInfoModel = BinaryDeepCopy(areaModel.PropertyInfoModel)
            };
            GlobleCache.areaList.Add(model);
        }

        /// <summary>
        /// 二进制序列化的方式进行深拷贝
        /// 确保需要拷贝的类里的所有成员已经标记为 [Serializable] 如果没有加该特性特报错
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T BinaryDeepCopy<T>(T t)
        {
            if (t is null) return t;
            //创建二进制序列化对象
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())//创建内存流
            {
                //将对象序列化到内存中
                bf.Serialize(ms, t);
                ms.Position = default;//将内存流的位置设为0
                return (T)bf.Deserialize(ms);//继续反序列化
            }
        }
    }
}
